home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / sys / msdos / msdos.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-16  |  10.4 KB  |  484 lines

  1. /*    SCCS Id: @(#)msdos.c     3.1     93/05/06          */
  2. /* Copyright (c) NetHack PC Development Team 1990, 1991, 1992      */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  *  MSDOS system functions.
  7.  *  Many thanks to Don Kneller who originated the DOS port and
  8.  *  contributed much to the cause.
  9.  */
  10.  
  11. #define NEED_VARARGS
  12. #include "hack.h"
  13.  
  14. #ifdef MSDOS
  15.  
  16. #include <dos.h>
  17. #include <ctype.h>
  18.  
  19. /*
  20.  * MS-DOS functions
  21.  */
  22. #define DIRECT_INPUT    0x07    /* Unfiltered Character Input Without Echo */
  23. #define FATINFO     0x1B    /* Get Default Drive Data */
  24. /* MS-DOS 2.0+: */
  25. #define GETDTA      0x2F    /* Get DTA Address */
  26. #define FREESPACE   0x36    /* Get Drive Allocation Info */
  27. #define GETSWITCHAR 0x3700  /* Get Switch Character */
  28. #define FINDFIRST   0x4E    /* Find First File */
  29. #define FINDNEXT    0x4F    /* Find Next File */
  30. #define SETFILETIME 0x5701  /* Set File Date & Time */
  31. /*
  32.  * BIOS interrupts
  33.  */
  34. #ifdef PC9801
  35. #define KEYBRD_BIOS 0x18
  36. #else
  37. #define KEYBRD_BIOS 0x16
  38. #endif
  39.  
  40. /*
  41.  * Keyboard BIOS functions
  42.  */
  43. #define READCHAR    0x00    /* Read Character from Keyboard */
  44. #define GETKEYFLAGS 0x02    /* Get Keyboard Flags */
  45.  
  46. void FDECL(get_cursor,(int *, int *));
  47.  
  48. #ifdef OVL0
  49.  
  50. /* direct bios calls are used only when flags.BIOS is set */
  51.  
  52. static char NDECL(DOSgetch);
  53. static char NDECL(BIOSgetch);
  54. static char * NDECL(getdta);
  55. static unsigned int FDECL(dos_ioctl, (int,int,unsigned));
  56.  
  57. int
  58. tgetch()
  59. {
  60.     char ch;
  61.  
  62.     /* BIOSgetch can use the numeric key pad on IBM compatibles. */
  63.     if (flags.BIOS)
  64.         ch = BIOSgetch();
  65.     else
  66.         ch = DOSgetch();
  67.     return ((ch == '\r') ? '\n' : ch);
  68. }
  69.  
  70.  
  71.  
  72. /*
  73.  *  Keyboard translation tables.
  74.  */
  75. #ifdef PC9801
  76. #define KEYPADLO    0x38
  77. #define KEYPADHI    0x50
  78. #else
  79. #define KEYPADLO    0x47
  80. #define KEYPADHI    0x53
  81. #endif
  82.  
  83. #define PADKEYS     (KEYPADHI - KEYPADLO + 1)
  84. #define iskeypad(x)    (KEYPADLO <= (x) && (x) <= KEYPADHI)
  85.  
  86. /*
  87.  * Keypad keys are translated to the normal values below.
  88.  * When flags.BIOS is active, shifted keypad keys are translated to the
  89.  *    shift values below.
  90.  */
  91. static const struct pad {
  92.     char normal, shift, cntrl;
  93. } keypad[PADKEYS] = {
  94. #ifdef PC9801
  95.             {'>', '>', '>'},        /* Ins */
  96.             {'<', '<', '<'},        /* Del */
  97.             {'k', 'K', C('k')},        /* Up */
  98.             {'h', 'H', C('h')},        /* Left */
  99.             {'l', 'L', C('l')},        /* Right */
  100.             {'j', 'J', C('j')},        /* Down */
  101.             { 0 ,  0 ,  0 },        /* HomeClr */
  102.             {'?', '?', '?' },        /* Help */
  103.             {'m', C('p'), C('p')},        /* - */
  104.             {'/', '/', '/'},        /* / */
  105.             {'y', 'Y', C('y')},        /* 7 */
  106.             {'k', 'K', C('k')},        /* 8 */
  107.             {'u', 'U', C('u')},        /* 9 */
  108.             {'*', '*', '*'},        /* * */
  109.             {'h', 'H', C('h')},        /* 4 */
  110.             {'g', 'g', 'g'},        /* 5 */
  111.             {'l', 'L', C('l')},        /* 6 */
  112.             {'p', 'P', C('p')},        /* + */
  113.             {'b', 'B', C('b')},        /* 1 */
  114.             {'j', 'J', C('j')},        /* 2 */
  115.             {'n', 'N', C('n')},        /* 3 */
  116.             {'=', '=', '='},        /* = */
  117.             {'i', 'I', C('i')},        /* 0 */
  118.             {',' ':', ':'},         /* , */
  119.             {'.', '.', '.'}         /* . */
  120. #else
  121.             {'y', 'Y', C('y')},        /* 7 */
  122.             {'k', 'K', C('k')},        /* 8 */
  123.             {'u', 'U', C('u')},        /* 9 */
  124.             {'m', C('p'), C('p')},        /* - */
  125.             {'h', 'H', C('h')},        /* 4 */
  126.             {'g', 'g', 'g'},        /* 5 */
  127.             {'l', 'L', C('l')},        /* 6 */
  128.             {'p', 'P', C('p')},        /* + */
  129.             {'b', 'B', C('b')},        /* 1 */
  130.             {'j', 'J', C('j')},        /* 2 */
  131.             {'n', 'N', C('n')},        /* 3 */
  132.             {'i', 'I', C('i')},        /* Ins */
  133.             {'.', ':', ':'}            /* Del */
  134. #endif
  135. }, numpad[PADKEYS] = {
  136. #ifdef PC9801
  137.             {'>', '>', '>'},        /* Ins */
  138.             {'<', '<', '<'},        /* Del */
  139.             {'8', M('8'), '8'},        /* Up */
  140.             {'4', M('4'), '4'},        /* Left */
  141.             {'6', M('6'), '6'},        /* Right */
  142.             {'2', M('2'), '2'},        /* Down */
  143.             { 0 ,  0 ,  0 },        /* HomeClr */
  144.             {'?', '?', '?'},        /* Help */
  145.             {'m', C('p'), C('p')},        /* - */
  146.             {'/', '/', '/'},        /* / */
  147.             {'7', M('7'), '7'},        /* 7 */
  148.             {'8', M('8'), '8'},        /* 8 */
  149.             {'9', M('9'), '9'},        /* 9 */
  150.             {'*', '*', '*'},        /* * */
  151.             {'4', M('4'), '4'},        /* 4 */
  152.             {'g', 'G', 'g'},        /* 5 */
  153.             {'6', M('6'), '6'},        /* 6 */
  154.             {'p', 'P', C('p')},        /* + */
  155.             {'1', M('1'), '1'},        /* 1 */
  156.             {'2', M('2'), '2'},        /* 2 */
  157.             {'3', M('3'), '3'},        /* 3 */
  158.             {'=', '=', '='},        /* = */
  159.             {'i', 'I', C('i')},        /* 0 */
  160.             {',', ':', ':'},        /* , */
  161.             {'.', '.', '.'}         /* . */
  162. #else
  163.             {'7', M('7'), '7'},        /* 7 */
  164.             {'8', M('8'), '8'},        /* 8 */
  165.             {'9', M('9'), '9'},        /* 9 */
  166.             {'m', C('p'), C('p')},        /* - */
  167.             {'4', M('4'), '4'},        /* 4 */
  168.             {'g', 'G', 'g'},        /* 5 */
  169.             {'6', M('6'), '6'},        /* 6 */
  170.             {'p', 'P', C('p')},        /* + */
  171.             {'1', M('1'), '1'},        /* 1 */
  172.             {'2', M('2'), '2'},        /* 2 */
  173.             {'3', M('3'), '3'},        /* 3 */
  174.             {'i', 'I', C('i')},        /* Ins */
  175.             {'.', ':', ':'}            /* Del */
  176. #endif
  177. };
  178.  
  179. /*
  180.  * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII
  181.  * meaning unless assigned one by a keyboard conversion table, so the
  182.  * keyboard BIOS normally does not return a character code when Alt-letter
  183.  * is pressed.    So, to interpret unassigned Alt-letters, we must use a
  184.  * scan code table to translate the scan code into a letter, then set the
  185.  * "meta" bit for it.  -3.
  186.  */
  187. #ifdef PC9801
  188. #define SCANLO        0x5
  189. #else
  190. #define SCANLO        0x10
  191. #endif /* PC9801 */
  192.  
  193. static const char scanmap[] = {     /* ... */
  194. #ifdef PC9801
  195.              0,  0,  0,  0,  0,  0, '-','^','\\','\b',
  196.     '\t','q','w','e','r','t','y','u','i','o','p','@','[', '\n',
  197.     'a','s','d','f','g','h','j','k','l',';',':', ']',
  198.     'z','x','c','v','b','N','m',',','.','/'    /* ... */
  199. #else
  200.     'q','w','e','r','t','y','u','i','o','p','[',']', '\n',
  201.     0, 'a','s','d','f','g','h','j','k','l',';','\'', '`',
  202.     0, '\\', 'z','x','c','v','b','n','m',',','.','?'    /* ... */
  203. #endif /* PC9801 */
  204. };
  205.  
  206. #define inmap(x)    (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap))
  207.  
  208. /*
  209.  * BIOSgetch gets keys directly with a BIOS call.
  210.  */
  211. #ifdef PC9801
  212. #define SHIFT        0x1
  213. #define KANA        0x4
  214. #define GRPH        0x8
  215. #define CTRL        0x10
  216. #else
  217. #define SHIFT        (0x1 | 0x2)
  218. #define CTRL        0x4
  219. #define ALT        0x8
  220. #endif /* PC9801 */
  221.  
  222. static char
  223. BIOSgetch()
  224. {
  225.     unsigned char scan, shift, ch;
  226.     const struct pad *kpad;
  227.  
  228.     union REGS regs;
  229.  
  230.     /* Get scan code.
  231.      */
  232.     regs.h.ah = READCHAR;
  233.     int86(KEYBRD_BIOS, ®s, ®s);
  234.     ch = regs.h.al;
  235.     scan = regs.h.ah;
  236.     /* Get shift status.
  237.      */
  238.     regs.h.ah = GETKEYFLAGS;
  239.     int86(KEYBRD_BIOS, ®s, ®s);
  240.     shift = regs.h.al;
  241.  
  242.     /* Translate keypad keys */
  243.     if (iskeypad(scan)) {
  244.         kpad = flags.num_pad ? numpad : keypad;
  245.         if (shift & SHIFT)
  246.             ch = kpad[scan - KEYPADLO].shift;
  247.         else if (shift & CTRL)
  248.             ch = kpad[scan - KEYPADLO].cntrl;
  249.         else
  250.             ch = kpad[scan - KEYPADLO].normal;
  251.     }
  252.     /* Translate unassigned Alt-letters */
  253. #ifdef PC9801
  254.     if (shift & KANA)
  255.         return 0;
  256.     if ((shift & GRPH) && (ch >= 0x80)) {
  257. #else
  258.     if ((shift & ALT) && !ch) {
  259. #endif
  260.         if (inmap(scan))
  261.             ch = scanmap[scan - SCANLO];
  262.         return (isprint(ch) ? M(ch) : ch);
  263.     }
  264.     return ch;
  265. }
  266.  
  267. static char
  268. DOSgetch()
  269. {
  270.     union REGS regs;
  271.     char ch;
  272.     struct pad (*kpad)[PADKEYS];
  273.  
  274.     regs.h.ah = DIRECT_INPUT;
  275.     intdos(®s, ®s);
  276.     ch = regs.h.al;
  277.  
  278. #ifdef PC9801
  279.     if (ch < 0)    /* KANA letters and GRPH-shifted letters(?) */
  280.         ch = 0; /* munch it */
  281. #else
  282.     /*
  283.      * The extended codes for Alt-shifted letters, and unshifted keypad
  284.      * and function keys, correspond to the scan codes.  So we can still
  285.      * translate the unshifted cursor keys and Alt-letters.  -3.
  286.      */
  287.     if (ch == 0) {        /* an extended key */
  288.         regs.h.ah = DIRECT_INPUT;
  289.         intdos(®s, ®s);    /* get the extended key code */
  290.         ch = regs.h.al;
  291.  
  292.         if (iskeypad(ch)) {    /* unshifted keypad keys */
  293.             kpad = (void *)(flags.num_pad ? numpad : keypad);
  294.             ch = (*kpad)[ch - KEYPADLO].normal;
  295.         } else if (inmap(ch)) { /* Alt-letters */
  296.             ch = scanmap[ch - SCANLO];
  297.             if (isprint(ch)) ch = M(ch);
  298.         } else ch = 0;        /* munch it */
  299.     }
  300. #endif
  301.     return (ch);
  302. }
  303.  
  304. char
  305. switchar()
  306. {
  307.     union REGS regs;
  308.  
  309.     regs.x.ax = GETSWITCHAR;
  310.     intdos(®s, ®s);
  311.     return regs.h.dl;
  312. }
  313.  
  314. long
  315. freediskspace(path)
  316. char *path;
  317. {
  318.     union REGS regs;
  319.  
  320.     regs.h.ah = FREESPACE;
  321.     if (path[0] && path[1] == ':')
  322.         regs.h.dl = (toupper(path[0]) - 'A') + 1;
  323.     else
  324.         regs.h.dl = 0;
  325.     intdos(®s, ®s);
  326.     if (regs.x.ax == 0xFFFF)
  327.         return -1L;        /* bad drive number */
  328.     else
  329.         return ((long) regs.x.bx * regs.x.cx * regs.x.ax);
  330. }
  331.  
  332. #ifndef __GO32__
  333. /*
  334.  * Functions to get filenames using wildcards
  335.  */
  336. int
  337. findfirst(path)
  338. char *path;
  339. {
  340.     union REGS regs;
  341.     struct SREGS sregs;
  342.  
  343.     regs.h.ah = FINDFIRST;
  344.     regs.x.cx = 0;        /* attribute: normal files */
  345.     regs.x.dx = FP_OFF(path);
  346.     sregs.ds = FP_SEG(path);
  347.     intdosx(®s, ®s, &sregs);
  348.     return !regs.x.cflag;
  349. }
  350.  
  351. int
  352. findnext() {
  353.     union REGS regs;
  354.  
  355.     regs.h.ah = FINDNEXT;
  356.     intdos(®s, ®s);
  357.     return !regs.x.cflag;
  358. }
  359.  
  360. char *
  361. foundfile_buffer()
  362. {
  363.     return (getdta() + 30);
  364. }
  365.  
  366.  
  367. /* Get disk transfer area */
  368. static char *
  369. getdta()
  370. {
  371.     union REGS regs;
  372.     struct SREGS sregs;
  373.     char *ret;
  374.  
  375.     regs.h.ah = GETDTA;
  376.     intdosx(®s, ®s, &sregs);
  377. #   ifdef MK_FP
  378.     ret = MK_FP(sregs.es, regs.x.bx);
  379. #   else
  380.     FP_OFF(ret) = regs.x.bx;
  381.     FP_SEG(ret) = sregs.es;
  382. #   endif
  383.     return ret;
  384. }
  385.  
  386. long
  387. filesize(file)
  388. char *file;
  389. {
  390.     char *dta;
  391.  
  392.     if (findfirst(file)) {
  393.         dta = getdta();
  394.         return  (* (long *) (dta + 26));
  395.     } else
  396.         return -1L;
  397. }
  398.  
  399. #endif /* __GO32__ */
  400.  
  401. /*
  402.  * Chdrive() changes the default drive.
  403.  */
  404. void
  405. chdrive(str)
  406. char *str;
  407. {
  408. #  define SELECTDISK    0x0E
  409.     char *ptr;
  410.     union REGS inregs;
  411.     char drive;
  412.  
  413.     if ((ptr = index(str, ':')) != NULL) {
  414.         drive = toupper(*(ptr - 1));
  415.         inregs.h.ah = SELECTDISK;
  416.         inregs.h.dl = drive - 'A';
  417.         intdos(&inregs, &inregs);
  418.     }
  419.     return;
  420. }
  421.  
  422.  
  423. /* Use the IOCTL DOS function call to change stdin and stdout to raw
  424.  * mode.  For stdin, this prevents MSDOS from trapping ^P, thus
  425.  * freeing us of ^P toggling 'echo to printer'.
  426.  * Thanks to Mark Zbikowski (markz@microsoft.UUCP).
  427.  */
  428.  
  429. #define DEVICE        0x80
  430. #define RAW        0x20
  431. #define IOCTL        0x44
  432. #define STDIN        fileno(stdin)
  433. #define STDOUT        fileno(stdout)
  434. #define GETBITS        0
  435. #define SETBITS        1
  436.  
  437. static unsigned    int old_stdin, old_stdout;
  438.  
  439. void
  440. disable_ctrlP()
  441. {
  442.  
  443.     if (!flags.rawio) return;
  444.  
  445.     old_stdin = dos_ioctl(STDIN, GETBITS, 0);
  446.     old_stdout = dos_ioctl(STDOUT, GETBITS, 0);
  447.     if (old_stdin & DEVICE)
  448.         dos_ioctl(STDIN, SETBITS, old_stdin | RAW);
  449.     if (old_stdout & DEVICE)
  450.         dos_ioctl(STDOUT, SETBITS, old_stdout | RAW);
  451.     return;
  452. }
  453.  
  454. void
  455. enable_ctrlP()
  456. {
  457.     if (!flags.rawio) return;
  458.     if (old_stdin)
  459.         (void) dos_ioctl(STDIN, SETBITS, old_stdin);
  460.     if (old_stdout)
  461.         (void) dos_ioctl(STDOUT, SETBITS, old_stdout);
  462.     return;
  463. }
  464.  
  465. static unsigned int
  466. dos_ioctl(handle, mode, setvalue)
  467. int handle, mode;
  468. unsigned setvalue;
  469. {
  470.     union REGS regs;
  471.  
  472.     regs.h.ah = IOCTL;
  473.     regs.h.al = mode;
  474.     regs.x.bx = handle;
  475.     regs.h.dl = setvalue;
  476.     regs.h.dh = 0;            /* Zero out dh */
  477.     intdos(®s, ®s);
  478.     return (regs.x.dx);
  479. }
  480.  
  481. # endif /* OVLB */
  482.  
  483. #endif /* MSDOS */
  484.